#include "KgMiswordDb.h"
#include "QuFile.h"
#include "KpTestInfo.h"

KgMiswordDb::KgMiswordDb(const QString& logDir)
    : logDir_(logDir)
{
    auto texMat = QuFile::readTextMatrix<5>(miswordsFilePath_());
    for (auto& r : texMat) {
        std::array<int, 8> ar;
        for (int i = 0; i < 4; i++) {
            auto parts = r[i + 1].split('/');
            Q_ASSERT(parts.size() == 2);
            ar[i * 2] = parts[0].toInt();
            ar[i * 2 + 1] = parts[1].toInt();
        }

        miswords_.insert(r[0], ar);
    }
}

QString KgMiswordDb::miswordsFilePath_() const
{
    return logDir_ + "/miswords.log";
}

bool KgMiswordDb::save()
{
    QVector<std::array<QString, 5>> texMat;
    texMat.reserve(miswords_.size());

    for (auto [key, value] : miswords_.asKeyValueRange()) {
        std::array<QString, 5> row;
        row[0] = key;
        for (int i = 0; i < 4; i++)
            row[i+1] = QString("%1/%2").arg(value[i * 2]).arg(value[i * 2 + 1]);

        texMat.push_back(std::move(row));
    }

    return QuFile::writeTextMatrix(texMat, miswordsFilePath_());
}

void KgMiswordDb::update(const KpTestInfo& info, const QString& word, bool wrong)
{
    if (!wrong && !miswords_.contains(word))
        return;

    auto& ar = miswords_[word];
    if (ar[info.mode * 2] > 0 || wrong) // 如果此前没有答错，则不累加答对数
        ar[info.mode * 2 + !wrong]++;
}

int KgMiswordDb::countMis(const std::array<int, 8>& ar)
{
    return ar[0] + ar[2] + ar[4] + ar[6];
}

float KgMiswordDb::countMisScore_(const std::array<int, 8>& ar)
{
    return countMis(ar) - 0.5f * (ar[1] + ar[3] + ar[5] + ar[7]);
}

QList<QPair<QString, std::array<int, 8>>> KgMiswordDb::sort() const
{
    QList<QPair<QString, std::array<int, 8>>> res;
    for (auto [key, value] : miswords_.asKeyValueRange())
        res.append({ key, value });

    std::sort(res.begin(), res.end(), [](auto i1, auto i2) {
        return countMis(i1.second) > countMis(i2.second);
    });

    return res;
}

QStringList KgMiswordDb::topMiswords() const
{
    QList<QPair<QString, std::array<int, 8>>> res;
    for (auto [key, value] : miswords_.asKeyValueRange())
        res.append({ key, value });

    std::sort(res.begin(), res.end(), [](auto i1, auto i2) {
        return countMisScore_(i1.second) > countMisScore_(i2.second);
    });

    QStringList sl; sl.reserve(res.size());
    for (int i = 0; i < res.size(); i++)
        sl << res[i].first;
    return sl;
}
